#include "stdafx.h"
#include "DirectoryTree.h"
#include "FileDescriptorReal.h"
#include "../vfs/DirectoryLocation.h"

namespace ja2{ namespace vfs
{
	class DirectoryLocation::IteratorImpl : public ILocation::Iterator::IImplementation
	{
		// Attributes
	private:
		//! Actual location.
		DirCatalog_t::const_iterator m_Location;

		// Operations
	public:
		//! See base.
		virtual DirectoryPtr_t value() const;
		//! See base.
		virtual void increment();
		//! See base.
		virtual bool equal(IImplementation const &Right) const;
		//! See base.
		virtual Ptr_t clone() const;

		// Construction/Destruction
	public:
		IteratorImpl(DirCatalog_t::const_iterator const &Location);
	};

	DirectoryLocation::IteratorImpl::IteratorImpl(DirCatalog_t::const_iterator const &Location)
		: m_Location(Location)
	{
	}

	DirectoryPtr_t DirectoryLocation::IteratorImpl::value() const
	{
		return m_Location->second;
	}

	void DirectoryLocation::IteratorImpl::increment()
	{
		++m_Location;
	}

	bool DirectoryLocation::IteratorImpl::equal(IImplementation const &Right) const
	{
		return (m_Location == static_cast<IteratorImpl const &>(Right).m_Location);
	}

	DirectoryLocation::IteratorImpl::Ptr_t DirectoryLocation::IteratorImpl::clone() const
	{
		return Ptr_t(new IteratorImpl(m_Location));
	}

	//------------------------------//

	DirectoryLocation::DirectoryLocation(boost::filesystem::path const &MountPoint, boost::filesystem::path const &RealPath, boost::filesystem::path const &WrkPath)
		: m_RealPath(RealPath)
	{
		std::stack<boost::filesystem::path> dir_stack;
		// Traverse all subdirs
		for(dir_stack.push(boost::filesystem::path()); !dir_stack.empty();)
		{
			// Get dir
			auto dir = dir_stack.top();
			dir_stack.pop();
			// Create location
			std::unique_ptr<DirectoryTree> p_sub_dir(new DirectoryTree(MountPoint, boost::algorithm::to_upper_copy(dir.string())));
			// Iterate over content
			for(boost::filesystem::directory_iterator it(WrkPath/RealPath/dir), end; it != end; ++it)
			{
				// Isn't any hidden file
				if(!it->path().stem().empty())
				{
					// Regular file, add to sub dir
					if(boost::filesystem::is_regular_file(*it))
						p_sub_dir->add_file(FileDescriptorPtr_t(new FileDescriptorReal(boost::algorithm::to_upper_copy(it->path().filename().string()), *it)));
					// Directory
					else if(boost::filesystem::is_directory(*it))
						dir_stack.push(boost::algorithm::to_upper_copy((dir/it->path().filename()).string()));
				}
			}
			m_CatDirs[dir] = std::move(p_sub_dir);
		}
/*
		// contains local path
//		typedef vfs::TSubDir<WriteType> tSubDir;
//		typedef std::pair<vfs::Path,tSubDir*> tDirs;
//		std::queue<tDirs> qSubDirs;
//		qSubDirs.push(tDirs(vfs::Path(vfs::Const::EMPTY()),new tSubDir(this->m_mountPoint, this->m_realPath)));
//		m_catDirs[this->m_mountPoint] = qSubDirs.front().second;
		do
		{
			utf8string sFilename;
			tSubDir *pCurrentDir;
			vfs::Path oCurDir;
			pCurrentDir = qSubDirs.front().second;
			oCurDir = this->m_realPath;
			if( !qSubDirs.front().first.empty())
			{
				oCurDir += qSubDirs.front().first;
			}

			try
			{
				os::CIterateDirectory::EFileAttribute eFA;
				os::CIterateDirectory iterFS(oCurDir, vfs::Const::STAR());
				while ( iterFS.nextFile(sFilename, eFA) ) 
				{
					if (StrCmp::Equal(vfs::Const::DOT(),sFilename) || StrCmp::Equal(vfs::Const::DOTDOT(),sFilename) || StrCmp::Equal(vfs::Const::DOTSVN(),sFilename) )
					{
						continue;
					}
					if (eFA == os::CIterateDirectory::FA_DIRECTORY) 
					{
						vfs::Path sLocal = qSubDirs.front().first + sFilename;

						vfs::Path temp = this->m_mountPoint+sLocal;
						tSubDir *pNewDir = new tSubDir(sLocal, this->m_realPath+sLocal);
						qSubDirs.push(tDirs(sLocal,pNewDir));
						m_catDirs[temp] = pNewDir;
					}
					else 
					{
						pCurrentDir->addFile(vfs::Path(sFilename));
					}
				}
			}
			catch(CBasicException &ex)
			{
				// probably directory doesn't exist. abort or continue???
				// -> abort AND continue
				logException(ex);
				return false;
			}
			qSubDirs.pop();
		}while(!qSubDirs.empty());
		return true;
*/
	}

	DirectoryPtr_t DirectoryLocation::get_dir(boost::filesystem::path const &/*File*/) const
	{
		return DirectoryPtr_t();
	}

	bool DirectoryLocation::dir_exist(boost::filesystem::path const &/*File*/) const
	{
		return false;
	}
	
	boost::filesystem::path const &DirectoryLocation::get_path() const
	{
		return m_RealPath;
	}
	
	ILocation::Iterator DirectoryLocation::begin()
	{
		return Iterator(new IteratorImpl(m_CatDirs.begin()));
	}
	
	ILocation::Iterator DirectoryLocation::end()
	{
		return Iterator(new IteratorImpl(m_CatDirs.end()));
	}
} /*vfs*/} /*ja2*/